package leetcode_ago.top_k;
/**
 * 找出数组中最小的k个数。以任意顺序返回这k个数均可
 * 取小数用大堆
 * 0 <= len(arr) <= 100000
 * 0 <= k <= min(100000, len(arr))
 */

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

/**
 * 分析：
 * 找最小的k个数，topK问题，用到最大堆（注意JDK内部默认是最小堆，需要用到比较器）
 * 思路：
 * 1.边界：arr.length==0||k==0
 * 2.构建最大堆
 * 3.遍历原数组，优先级队列中只存储前个元素，不够k个一直存到k个，够了就判别，大元素出队
 * 4.最大堆（优先级队列）中元素依次出队即可
 */
public class Num17_14_SmallestK {
    public int[] smallestK(int[] arr, int k) {
        if(arr.length==0||k==0){
            return new int[0];
        }
        //构造最大堆（优先级队列内部默认最小堆）
        Queue<Integer> queue=new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        //遍历原数组元素，给队内添加元素，优先级队列只存储k个值。元素满了就判断当前添加元素与堆顶元素的大小
        //比堆顶元素大无需入队，比堆顶元素小则堆顶元素出队它入队
        for(int i:arr){
            if(queue.size()<k){
                queue.offer(i);
            }else{
                int peek=queue.peek();
                if(i>peek){
                    //元素>堆顶元素，不入队，进入下一个循环
                    continue;
                }else{
                    queue.poll();
                    queue.offer(i);
                }
            }
        }
        //循环完毕，最小的k个数已在队内（最大堆中就保存了最小的k个数），k个数依次出队即可
        int[] ret=new int[k];
        for (int i = 0; i < k; i++) {
            ret[i]=queue.poll();
        }
        return ret;
    }
}
